package play.modules.fbauth;


import net.rehman.fbauth.FbAuthHelper;
import play.Logger;
import play.Play;
import play.PlayPlugin;
import play.exceptions.ConfigurationException;
import play.mvc.Http;
import play.mvc.Http.Request;
import play.mvc.Http.Response;

import java.io.IOException;
import java.util.Map;


public class FbAuthPlugin extends PlayPlugin
{

    private static final String APP_ID = "fbauth.appId";

    private static final String API_KEY = "fbauth.apiKey";

    private static final String APP_SECRET = "fbauth.appSecret";

    private static final String PERMISSION = "fbauth.permissions";

    private static final String CANVAS_URL = "fbauth.canvasUrl";

    private static final String CANVAS_PAGE = "fbauth.canvasPage";

    private static final String SESSION_KEY = "fbauth_sigreg_" + Play.configuration.getProperty( APP_ID );

    private static final String FB_EXPIRES_KEY = "expires";

    private static final String FB_ISSUEAT_KEY = "issued_at";

    private static final String FB_OAUTH_KEY = "oauth_token";

    private static final String FB_SIGREQ_KEY = "signed_request";

    private String canvasUrl;

    private String canvasPage;

    private FbAuthHelper fbAuthHelper;

    @Override
    public void onLoad()
    {
        //load all config
        setFbAuthHelper( loadFbAuthConfig() );
        super.onLoad();

    }

    private FbAuthHelper loadFbAuthConfig()
    {
        if ( !Play.configuration.containsKey( APP_ID ) ||
                !Play.configuration.containsKey( API_KEY ) ||
                !Play.configuration.containsKey( APP_SECRET )
                )
        {
            throw new ConfigurationException( "Either fbauth.app_id , fbauth.apiKey or fbauth.appSecret not Configured" );

        }
        else
        {
            setCanvasUrl( Play.configuration.getProperty( CANVAS_URL, null ) );
            setCanvasPage( Play.configuration.getProperty( CANVAS_PAGE, null ) );
            return new FbAuthHelper( Play.configuration.getProperty( APP_ID ),
                                     Play.configuration.getProperty( APP_SECRET ),
                                     Play.configuration.getProperty( PERMISSION, null ) );
        }
    }


    public Map<String, Object> getFbUser() throws IOException, FbAuthException
    {
        return getFbUser( getCurrentCanvasUrl() );
    }

    public Map<String, Object> getFbUser( String FbCallbackURL ) throws IOException, FbAuthException
    {
        Request request = Http.Request.current();

        Response response = Http.Response.current();

        String signed_request = null;
        try
        {
            if ( request.cookies.containsKey( SESSION_KEY ) )
            {
                signed_request = request.cookies.get( SESSION_KEY ).value;
                if ( signed_request == null || signed_request.equals( "" ) )
                {
                    signed_request = request.params.allSimple().get( FB_SIGREQ_KEY );
                }
            }
            else if ( request.params.allSimple().containsKey( FB_SIGREQ_KEY ) )
            {
                signed_request = request.params.allSimple().get( FB_SIGREQ_KEY );
            }


            Logger.debug( signed_request );

            Map<String, Object> fbUser = getFbAuthHelper().parseSignedRequest( signed_request );

            if ( !getFbAuthHelper().isAuthorized( fbUser ) || !fbUser.containsKey( FB_OAUTH_KEY ) )
            {
                //redirects user,  authorizing permission invalidate cookie need
                throw new FbAuthException( "Facebook authorization required",
                                           getFbAuthHelper().getAuthRedirectHtml( FbCallbackURL ),
                                           getFbAuthHelper().buildFacebookAuthorizeUrl( FbCallbackURL ),
                                           response
                );
            }

            if ( !request.cookies.containsKey( SESSION_KEY ) )
            {
                long expires = ( ( Integer ) fbUser.get( FB_EXPIRES_KEY ) ).longValue();
                long issueAt = ( ( Integer ) fbUser.get( FB_ISSUEAT_KEY ) ).longValue();
            
                if ( fbUser.get( FB_EXPIRES_KEY ).toString().equals( "0" ) )
                {
                    response.setCookie( SESSION_KEY, signed_request, "1m" );
                }
                else
                {
                    response.setCookie( SESSION_KEY, signed_request, expires + "s" );
                }

                Logger.info( response.cookies.toString() );

            }
            return fbUser;
        }
        catch ( Exception e )
        {
            clearCachedSignRequest();
            //catch all exception and repackage it with FbAuthExceptions
            throw new FbAuthException( e.getMessage(),
                                       getFbAuthHelper().getAuthRedirectHtml( FbCallbackURL ),
                                       getFbAuthHelper().buildFacebookAuthorizeUrl( FbCallbackURL ),
                                       response
            );

        }
    }

    public void clearCachedSignRequest()
    {
        Response response = Http.Response.current();
        Request request = Http.Request.current();
        response.removeCookie( SESSION_KEY );
        if ( request.cookies.containsKey( SESSION_KEY ) )
        {
            request.cookies.remove( SESSION_KEY );
        }
    }

    public String getCurrentCanvasUrl()
    {
        if ( getCanvasUrl() == null || getCanvasPage() == null )
        {
            throw new ConfigurationException( "canvasUrl, canvasPage not configured" );
        }
        else if ( !getCanvasPage().contains( "http://apps.facebook.com/" ) )
        {
            throw new ConfigurationException( "canvasPage, should under apps.facebook domain" );
        }
        Request req = Http.Request.current();

        String fullUrl = req.getBase() + req.url;

        String tailingUrl = fullUrl.substring( getCanvasUrl().length(), fullUrl.length() );

        return getCanvasPage() + tailingUrl;
    }

    public FbAuthHelper getFbAuthHelper()
    {
        return fbAuthHelper;
    }

    public void setFbAuthHelper( FbAuthHelper fbAuthHelper )
    {
        this.fbAuthHelper = fbAuthHelper;
    }


    public String getCanvasUrl()
    {
        if ( canvasUrl == null )
        {
            return Request.current().getBase();
        }
        return canvasUrl;
    }

    public void setCanvasUrl( String canvasUrl )
    {
        this.canvasUrl = canvasUrl;
    }

    public String getCanvasPage()
    {
        return canvasPage;
    }

    public void setCanvasPage( String canvasPage )
    {
        this.canvasPage = canvasPage;
    }
}
